package org.op.editor;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.StyledDocument;
import javax.swing.undo.UndoManager;

import org.op.editor.doc.EditorLoadController;
import org.op.service.WwDocumentInfo;

public class EditorComponentTextPaneViewImpl implements EditorComponentView, MouseListener {

	private Component component;
	private JTabbedPane tabbedPane;
	private EditorLoadController editorController;
	private PopupMenuView popupMenuView;
	private PopupMenuView tabPopupMenuView;
	private OpenCloseController openCloseController;
	
	private Action editorKeyAction;

	private UndoManager undoManager;
	
	private Map<WwDocumentInfo, JEditorPane> editorPanes;
	
	public static final String DIRTY_FLAG = "*";
	
	public EditorComponentTextPaneViewImpl() {
		editorPanes = new HashMap<WwDocumentInfo, JEditorPane>();
	}
	
	public void build() {
        tabbedPane = new JTabbedPane(SwingConstants.TOP);
        tabbedPane.setBorder(new EmptyBorder(10, 10, 10, 10));
        tabbedPane.addMouseListener(this);
        component = tabbedPane;
        
        undoManager = new UndoManager();
	}
	
	public void addEditor(Document content, WwDocumentInfo docInfo) {
        
        JTextPane editor = new JTextPane((StyledDocument)content);
        content.addUndoableEditListener(new UndoableEditListener() {
			public void undoableEditHappened(UndoableEditEvent event) {
				if (event.getEdit()!=null) {
					undoManager.addEdit(event.getEdit());	
				}
			}
        });
        
        Border border = new CompoundBorder(BorderFactory.createLineBorder(Color.GRAY), new EmptyBorder(5,5,5,5));
        editor.setBorder(border);
        	       
        editor.addMouseListener(this);  // is this necessary, since nested under tabbed pane?
        editor.setName(docInfo.getName());
        
        editor.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0),"checkWW");
        editor.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"checkWW");
        editor.getActionMap().put("checkWW",editorKeyAction);
        
        JScrollPane scrollPane = new JScrollPane(editor);
        scrollPane.setBorder(null);
        
        // make sure the document is not already open
        Set<WwDocumentInfo> exDocInfos = editorPanes.keySet();
        boolean docOpen = false;
        for (WwDocumentInfo exDocInfo : exDocInfos) {
        	if (exDocInfo.equals(docInfo)) {
        		docOpen = true;
            	JEditorPane openedPane = editorPanes.get(exDocInfo);
            	if (openedPane!=null) {
            		// why is this next line necessary?
            		openedPane.setDocument(content);
            		JScrollPane editorScrollPane = (JScrollPane) openedPane.getParent().getParent();
            		tabbedPane.setSelectedComponent(editorScrollPane);
            	}
        	}
        }
        
        if (!docOpen) {
        	// DONT BIND the docInfo of the editor with the Tree! - problems with SaveAs
        	//  Create a new docInfo object
        	WwDocumentInfo newInfo = new WwDocumentInfo(docInfo.getName(), docInfo.getFilepath());
        	tabbedPane.add(docInfo.getName(),scrollPane);
        	tabbedPane.setSelectedComponent(scrollPane);
        	editorPanes.put(newInfo, editor);
        }
       
	}
	
	public JEditorPane getCurrentPane() {
		JTextPane editor = null;
		JScrollPane scrollPane = (JScrollPane) tabbedPane.getSelectedComponent();
		if (scrollPane!=null) {
			editor = (JTextPane)scrollPane.getViewport().getView();
		}
		return editor;
	}
	

	public WwDocumentInfo getCurrentDocumentInfo() {
		JEditorPane editor = getCurrentPane();
		
		WwDocumentInfo currentInfo = null;
		Set<WwDocumentInfo> exDocInfos = editorPanes.keySet();
		for (WwDocumentInfo exDocInfo : exDocInfos) {
			JEditorPane exEditor = editorPanes.get(exDocInfo);
			if (exEditor.equals(editor)) {
				currentInfo = exDocInfo;
			}
		}
		
		return currentInfo;
	}
	

	public void setCurrentDocumentInfo(WwDocumentInfo docInfo) {
		JEditorPane editor = getCurrentPane();
		
		WwDocumentInfo exDocInfo = getCurrentDocumentInfo();
		exDocInfo.setName(docInfo.getName());
		exDocInfo.setFilepath(docInfo.getFilepath());

		editor.setName(docInfo.getName());
		
		// update the tab title
		int i = tabbedPane.getSelectedIndex();
		tabbedPane.setTitleAt(i, docInfo.getName());
	}
	
	public void setCurrentDirty() {
		int i = tabbedPane.getSelectedIndex();
		String title = tabbedPane.getTitleAt(i);
		if (!title.startsWith(EditorComponentTextPaneViewImpl.DIRTY_FLAG)) {
			title = EditorComponentTextPaneViewImpl.DIRTY_FLAG + title;
			tabbedPane.setTitleAt(i, title);
		}
	}
	
	public void setDirty(String documentName) {
		int tabs = tabbedPane.getTabCount();
		for (int i=0; i<tabs; i++) {
			String title = tabbedPane.getTitleAt(i);
			if (title.equalsIgnoreCase(documentName)) {
				title = DIRTY_FLAG + title;
				tabbedPane.setTitleAt(i, title);
			}
		}
	}
	
	public boolean isCurrentDirty() {
		boolean dirty = false;
		int i = tabbedPane.getSelectedIndex();
		String title = tabbedPane.getTitleAt(i);
		if (title.startsWith(EditorComponentTextPaneViewImpl.DIRTY_FLAG)) {
			dirty = true;
		}
		
		return dirty;
	}
	
	public void setClean(String documentName) {
		int tabs = tabbedPane.getTabCount();
		for (int i=0; i<tabs; i++) {
			String title = tabbedPane.getTitleAt(i);
			if (title.equalsIgnoreCase(DIRTY_FLAG + documentName)) {
				title = removeDirtyFlag(title);
				tabbedPane.setTitleAt(i, title);
			}
		}
	}
	
	private String removeDirtyFlag (String name) {
		if (name.startsWith(DIRTY_FLAG)) {
			name = name.substring(1);
		}
		return name;
	}
	
	public void removeSelectedEditor() {
		// remove map entry
		WwDocumentInfo currentInfo = getCurrentDocumentInfo();
		editorPanes.remove(currentInfo);
		
		// remove editor
		int currentPane = tabbedPane.getSelectedIndex();
		if (currentPane>=0) {
			tabbedPane.remove(currentPane);
		}
	}
	
	public String getSelectedText() {
		
		JEditorPane editorPane = getCurrentPane();
		// editorPane.getSelectedText(); -- This method doesnt work with swingwt
		
		Document doc = editorPane.getDocument();
		int startIdx = editorPane.getSelectionStart();
		int endIdx = editorPane.getSelectionEnd();
		String selectedText = "";  // should we make this null?
		try {
			selectedText = doc.getText(startIdx, (endIdx - startIdx));
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
		return selectedText;
	}

	public void redoLastEdit() {
		undoManager.redo();
	}

	public void undoLastEdit() {
		undoManager.undo();
	}

	public void mouseClicked(MouseEvent me) {

		if (me.getSource() instanceof JTextPane) {
			JTextPane editor = (JTextPane)me.getSource();
			if (me.getClickCount()==2) {
				String word = getSelectedText();
				openCloseController.openWikiwordDocument(word);		
			} else {
				// right click context menu?
				if (me.getButton() == MouseEvent.BUTTON3) {
					popupMenuView.showMenu(editor, me.getPoint());
				}
			}
		}
		
		if (me.getSource() instanceof JTabbedPane) {
			if (me.getButton() == MouseEvent.BUTTON3) {
				tabPopupMenuView.showMenu(tabbedPane, me.getPoint());
			}
		}
		
	}

	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public PopupMenuView getPopupMenuView() {
		return popupMenuView;
	}

	public void setPopupMenuView(PopupMenuView popupMenuView) {
		this.popupMenuView = popupMenuView;
	}

	public Component getComponent() {
		return component;
	}

	public void setComponent(Component component) {
		this.component = component;
	}

	public EditorLoadController getEditorController() {
		return editorController;
	}

	public void setEditorController(EditorLoadController editorController) {
		this.editorController = editorController;
	}

	public PopupMenuView getTabPopupMenuView() {
		return tabPopupMenuView;
	}

	public void setTabPopupMenuView(PopupMenuView tabPopupMenuView) {
		this.tabPopupMenuView = tabPopupMenuView;
	}

	public Action getEditorKeyAction() {
		return editorKeyAction;
	}

	public void setEditorKeyAction(Action editorKeyAction) {
		this.editorKeyAction = editorKeyAction;
	}

	public OpenCloseController getOpenCloseController() {
		return openCloseController;
	}

	public void setOpenCloseController(OpenCloseController openCloseController) {
		this.openCloseController = openCloseController;
	}

	public Map<WwDocumentInfo, JEditorPane> getEditorPanes() {
		return editorPanes;
	}

	public void setEditorPanes(Map<WwDocumentInfo, JEditorPane> editorPanes) {
		this.editorPanes = editorPanes;
	}


}
